package io.github.leon406.capp.engine.net

import android.app.Application
import android.util.Log
import com.lzy.okgo.OkGo
import com.lzy.okgo.cache.CacheEntity
import com.lzy.okgo.cache.CacheMode
import com.lzy.okgo.callback.FileCallback
import com.lzy.okgo.interceptor.HttpLoggingInterceptor
import com.lzy.okgo.model.HttpHeaders
import com.lzy.okgo.model.HttpParams
import com.lzy.okgo.model.Progress
import com.lzy.okgo.model.Response
import com.lzy.okrx2.adapter.ObservableBody
import io.github.leon406.capp.engine.net.internal.FixFileCallback
import io.github.leon406.capp.extension.switch2Ui
import io.reactivex.Observable
import io.reactivex.ObservableTransformer
import okhttp3.OkHttpClient
import org.json.JSONObject
import java.io.File
import java.util.concurrent.TimeUnit
import java.util.logging.Level.INFO


/**
 * Gson OkRx2
 */
object OkRx2Manager {

    fun init(app: Application) {
        val headers = HttpHeaders()
        headers.put("Connection", "keep-alive")
        headers.put("Content-Type", "application/json")

        val builder = OkHttpClient.Builder()
        val loggingInterceptor = HttpLoggingInterceptor("OkGo")
        loggingInterceptor.setPrintLevel(HttpLoggingInterceptor.Level.BODY)
        loggingInterceptor.setColorLevel(INFO)
        builder.addInterceptor(loggingInterceptor)
                .readTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS)
                .writeTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS)
                .connectTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS)

        OkGo.getInstance().init(app)
                .setOkHttpClient(builder.build())
                .setCacheMode(CacheMode.NO_CACHE)
                .setCacheTime(CacheEntity.CACHE_NEVER_EXPIRE)
                .setRetryCount(3)
                .addCommonHeaders(headers)
    }

    fun <T> get(url: String, params: HttpParams, clazz: Class<T>) = OkGo.get<T>(url)
            .params(params)
            .converter(GsonConvert(clazz))
            .adapt(ObservableBody())
            .switch2Ui()


    fun <T> getData(url: String, params: HttpParams, clazz: Class<T>) = get(url, params, String::class.java)
            .compose(errorTransform())
            .map {
                Convert.fromJson(it.optString("data"), clazz)
            }

    /**
     * @param <T>
     * @return
     * @Desc 线程切换 使用io密集型操作， 例如网络请求,数据库操作
    </T> */
    fun errorTransform(): ObservableTransformer<String, JSONObject>  = ObservableTransformer {
        it.map { JSONObject(it) }.filter {
            val code = it.optInt("code")
            val msg = it.optString("message")
            if (code != 0) {
                println("ERROR CODE $code $msg")
                throw NetException(code.toString(),Throwable(msg))
            }
            code == 0
        }
    }


    fun <T> post(url: String, params: HttpParams, clazz: Class<T>) = OkGo.post<T>(url)
            .headers("Content-Type", "application/json")
            .params(params)
            .converter(GsonConvert(clazz))
            .adapt(ObservableBody())
            .switch2Ui()


    fun <T> postJson(url: String, json: String, clazz: Class<T>) = OkGo.post<T>(url)
            .headers("Content-Type", "application/json")
            .upJson(json)
            .converter(GsonConvert(clazz))
            .adapt(ObservableBody())
            .switch2Ui()


    interface OnFileDownloadListener {

        fun onFileDownloaded(file: File)
    }


    fun downloadFile(url: String, folder: String, fileName: String,
                     listener: OnFileDownloadListener?): Observable<Progress> {
        return Observable.create { emitter ->
            OkGo.get<File>(url)//
                    //                        .params(params)//
                    .headers("Content-Type", "application/octet-stream")
                    .execute(object : FileCallback(folder, fileName) {
                        override fun onSuccess(response: Response<File>) {
                            Log.d("OkRx2Manager", response.body().absolutePath)
                            listener?.onFileDownloaded(response.body().absoluteFile)

                            emitter.onComplete()
                        }

                        override fun onError(response: Response<File>) {
                            Log.d("OkRx2Manager err", if (response.body() == null) " empty file" else response.body().absolutePath)
                            emitter.onError(response.exception)
                        }

                        override fun downloadProgress(progress: Progress?) {
                            emitter.onNext(progress!!)
                        }
                    })
        }
    }

    /**
     * 下载有回调
     *
     * @param url
     * @return
     */

    fun downloadFile2(url: String, //HttpParams params,
                      listener: OnFileDownloadListener?): Observable<Progress> {
        return Observable.create { emitter ->
            OkGo.get<File>(url)//
                    //                        .params(params)//
                    .headers("Content-Type", "application/octet-stream")
                    .execute(object : FixFileCallback() {
                        override fun onSuccess(response: Response<File>) {
                            Log.d("OkRx2Manager", response.body().absolutePath)
                            listener?.onFileDownloaded(response.body().absoluteFile)

                            emitter.onComplete()
                        }

                        override fun onError(response: Response<File>) {
                            //                                Log.d("OkRx2Manager err", response.body().getAbsolutePath());
                            emitter.onError(response.exception)
                        }

                        override fun downloadProgress(progress: Progress?) {
                            emitter.onNext(progress!!)
                        }
                    })
        }
    }

    fun <T> uploadFiles(url: String, params: HttpParams, files: List<File>, clazz: Class<T>) = OkGo.post<T>(url)
            .params(params)
            .addFileParams("file", files)
            .converter(GsonConvert())
            .adapt(ObservableBody())
            .switch2Ui()

    fun <T> uploadFile(url: String, params: HttpParams, file: File, clazz: Class<T>) = OkGo.post<T>(url)
            .params(params)
            .params("img", file)
            .converter(GsonConvert())
            .adapt(ObservableBody())
            .switch2Ui()
}
